home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
TCL1
/
JOHNLOVE
/
C_SOURCE
/
CMETER.C
< prev
next >
Wrap
Text File
|
1992-02-22
|
11KB
|
425 lines
/********************************************************************
"CMeter.c"
by: Walt Davis [MacTutor, September 1991]
converted to "C" & OOP by: John A. Love, III
using Symantec's "THINK C", v 5.0.1
********************************************************************/
#include <CDecorator.h>
#include <CDesktop.h>
#include <CWindow.h>
#include <TBUtilities.h>
#include "CmyGlobals.h"
#include "CmyMisc.h"
#include "CMeter.h"
extern CDesktop *gDesktop;
extern CDecorator *gDecorator;
void CMeter::IMeter (short WINDid, LongFunc calculateProgress,
Str255 bannerStr, short maxSteps,
CApplication *itsSupervisor) {
CMeterMainPane *mainMeterPane = nil;
short windowTooSmall = -10000, deltaH, deltaV;
// Frame assumes portRect = 292 X 60. Will be adjusted on the fly:
Rect progressR = {22, 16, 22+16, 16+260};
LongRect enclRect;
Rect enclR, dNewBarSize;
CProgressBorder *roundRect = nil;
CDocument::IDocument(itsSupervisor, false);
itsWindow = new (CWindow);
itsWindow->IWindow (WINDid, true /* floating */, gDesktop, this);
// First sub-view:
mainMeterPane = new (CMeterMainPane);
mainMeterPane->IPane(
itsWindow,
this,
0, 0, 0, 0,
sizELASTIC, sizELASTIC
);
mainMeterPane->FitToEnclosure(true, true);
itsMainPane = mainMeterPane;
;
CopyPString(bannerStr, mainMeterPane->mTitle);
calc = calculateProgress; /* Used by CMakingProgress::Calculate */
// Second sub-view <instance variable in CMeter>:
meterProgressBar = new (CProgressBar);
meterProgressBar->IPane(mainMeterPane, this, 0, 0, 0, 0, sizELASTIC, sizELASTIC);
meterProgressBar->FitToEnclosure(true, true);
// Sub-view's border:
roundRect = new (CProgressBorder);
roundRect->IPaneBorder(kBorderRoundRect);
meterProgressBar->SetBorder(roundRect);
// Adjust frame size on the fly:
meterProgressBar->GetFrame(&enclRect);
/* Default value of CView::usingLongCoord = false,
** so the frame is already in QuickDraw coordinates:
** meterProgressBar->FrameToQDR(&enclRect, &enclR); */
LongToQDRect(&enclRect, &enclR);
deltaH = enclR.right - (progressR.right + progressR.left);
deltaV = enclR.bottom - (progressR.bottom + progressR.top );
if (deltaH < 0 || deltaV < 0) Failure(windowTooSmall, kSilentErr);
else {
deltaV = (deltaV % 16) / 2;
deltaH = (deltaH % 10) / 2;
SetRect(
&dNewBarSize,
progressR.left + deltaH,
progressR.top + deltaV,
-(progressR.left + deltaH),
-(progressR.top + deltaV)
);
/* ChangeSize still maintains topLeft of frame = {0, 0}.
** However, pane's {vOrigin, hOrigin} = - dNewBarSize.topLeft. */
meterProgressBar->ChangeSize(&dNewBarSize, false /* do NOT redraw */);
/* Another sub-view <second instance variable in CMeter>:
** Note that this overlaps exactly its enclosure because
** the enclosure draws the oval frame border and the tick
** marks, whereas the sub-view draws the moving progress. */
progressO = new (CMakingProgress);
progressO->IPane(meterProgressBar, this, 0, 0, 0, 0, sizELASTIC, sizELASTIC);
progressO->FitToEnclosure(true, true);
progressO->start = false;
progressO->maxSteps = maxSteps;
progressO->currStep = 0;
itsGopher = progressO;
/* System 7 WIND resource automatically centers: */
if ( !WINDResourceHasSystem7Field(itsWindow) ) {
short saveProcID = itsWindow->procID;
itsWindow->SetModal(false);
// Gotta do this kludge because CenterWindow tests isModal
// AND the window's procID:
itsWindow->procID = 0;
gDecorator->CenterWindow(itsWindow);
itsWindow->procID = saveProcID;
}
} /* Window big enough */
} /* CMeter::IMeter */
void CMeterMainPane::Draw (Rect *area) {
CWindow *myWindow;
CMeter *mySupervisingDoc;
PenState pnState;
RGBColor foreColor,
myRed = {65535, 0, 0},
myBlue = { 0, 0, 65535};
LongRect windRect, barRect;
Rect windR, box;
short stringLen;
myWindow = GetWindow();
myWindow->GetInterior(&windRect);
LongToQDRect(&windRect, &windR);
EraseRect(&windR);
mySupervisingDoc = (CMeter*) GetSupervisor();
mySupervisingDoc->meterProgressBar->GetFrame(&barRect);
/* Once again, we are NOT using long coordinates.
** But, we ARE drawing in meterProgressBar's window ... */
mySupervisingDoc->meterProgressBar->FrameToWindR(&barRect, &box);
GetPenState(&pnState);
if (gSystem.hasColorQD) GetForeColor(&foreColor);
PenNormal();
TextFont(systemFont);
TextSize(12);
// Draw the "horizontal axis" of the dynamic rect:
if (gSystem.hasColorQD) RGBForeColor(&myRed);
MoveTo(box.left - 5, box.bottom + 16);
DrawString("\p0%");
MoveTo(box.right - 185, box.bottom + 16);
DrawString("\pPercent Complete");
MoveTo(box.right - 20, box.bottom + 16);
DrawString("\p100%");
// Draw the window's "title":
stringLen = StringWidth(mTitle);
if (stringLen <= frame.right - frame.left) {
if (gSystem.hasColorQD) RGBForeColor(&myBlue);
MoveTo(frame.left + (frame.right - frame.left - stringLen) / 2, box.top - 9);
DrawString(mTitle);
}
if (gSystem.hasColorQD) RGBForeColor(&foreColor);
SetPenState(&pnState);
} /* CMeterMainPane::Draw */
void CProgressBorder::IPaneBorder (short borderFlags) {
Rect roundMargin = {0, 0, 0, 0}; /* Border touches Pane */
inherited::IPaneBorder(borderFlags);
SetPenSize(1, 1);
SetRounding(16, 16);
SetMargin(&roundMargin);
} /* CProgressBorder::IPaneBorder */
void CProgressBorder::DrawBorder (Rect *paneFrame) {
RGBColor saveColor, myRed = {65535, 0, 0};
if (gSystem.hasColorQD) {
GetForeColor(&saveColor);
RGBForeColor(&myRed);
}
inherited::DrawBorder(paneFrame);
if (gSystem.hasColorQD) RGBForeColor(&saveColor);
} /* CProgressBorder::DrawBorder */
void CProgressBar::Draw (Rect *area) {
/* Where the 5% and 10% graduation marks are placed
** given a rect 260 pixels wide by 16 pixels tall.
** These are changed on the fly based on frame size: */
short fiveSize, fiveStep; /* 2, 13 */
short tenSize , tenStep ; /* 4, 26 */
PenState pnState;
RGBColor foreColor, backColor,
myRed = {65535, 0, 0},
myYellow = {65535, 61612, 1737};
LongRect progressRect;
Rect box;
short pnSize = 1, grad, hDiameter, vDiameter;
GetFrame(&progressRect);
LongToQDRect(&progressRect, &box);
/* We could ignore the top-left coordinate because it's
** zero since we are not scrolling the pane. Let's
** leave it be, however, to highlight the math: */
fiveSize = (box.bottom - box.top )/8;
tenSize = fiveSize * 2;
fiveStep = (box.right - box.left)/20;
tenStep = fiveStep * 2;
GetPenState(&pnState);
if (gSystem.hasColorQD) {
GetForeColor(&foreColor);
GetBackColor(&backColor);
RGBForeColor(&myRed);
RGBBackColor(&myYellow);
}
PenNormal();
PenSize(pnSize, pnSize);
itsBorder->GetRounding(&hDiameter, &vDiameter);
EraseRoundRect(&box, hDiameter, vDiameter);
// Draw the first 5% graduation mark:
MoveTo(box.left + fiveStep, box.top);
Line(0, fiveSize);
MoveTo(box.left + fiveStep, box.bottom);
Line(0, -fiveSize);
// Draw the remaining graduation Marks:
for (grad = 1; grad <= 9; grad++) {
MoveTo(box.left + grad*tenStep, box.top);
Line(0, tenSize); /* from top */
MoveTo(box.left + grad*tenStep, box.bottom);
Line(0, -tenSize); /* from bottom */
MoveTo(box.left + grad*tenStep + fiveStep, box.top);
Line(0, fiveSize);
MoveTo(box.left + grad*tenStep + fiveStep, box.bottom);
Line(0, -fiveSize);
}
if (gSystem.hasColorQD) {
RGBForeColor(&foreColor);
RGBBackColor(&backColor);
}
SetPenState(&pnState);
} /* CProgressBar::Draw */
void CMakingProgress::Draw (Rect *area) {
CMeter *mySupervisingDoc;
CProgressBorder *myBorder;
RGBColor saveColor, myGreen = {0, 65535, 0};
LongRect progressBar;
Rect progress;
short hDiameter, vDiameter;
long pDone;
if (!start || maxSteps == 0) return;
/* _FillRoundRect overwrites the frame for VERY small rectangles: */
if (currStep < 6) return;
GetFrame(&progressBar);
LongToQDRect(&progressBar, &progress);
if (gSystem.hasColorQD) {
GetForeColor(&saveColor);
RGBForeColor(&myGreen);
}
/* A kludgy way to round-up ... BUT it works !!
** ... it sure beats using the full ANSI library
** which significantly increases the Project size: */
pDone = ((long)currStep * 10000) / maxSteps;
if (pDone > ( (( (long)currStep*100 )/maxSteps) * 100 )) pDone = pDone/100 + 1;
else pDone = pDone/100;
if (pDone > 100) pDone = 100;
;
progress.right = progress.left +
(pDone * (progress.right - progress.left))/100;
mySupervisingDoc = (CMeter*) GetSupervisor();
myBorder = (CProgressBorder*) ( mySupervisingDoc->meterProgressBar->GetBorder() );
myBorder->GetRounding(&hDiameter, &vDiameter);
FillRoundRect(&progress, hDiameter, vDiameter, <Gray);
ValidRect(&progress); /* No pesky updates !! */
if (gSystem.hasColorQD) RGBForeColor(&saveColor);
} /* CMakingProgress::Draw */
short CMakingProgress::Calculate (void) {
/* The Function passed to IMeter determines the % progress
** you've made, say in spooling a file to the printer. Here
** we need to convert this % to a step number: */
CMeter *mySupervisingDoc;
long percentProgress;
mySupervisingDoc = (CMeter*) GetSupervisor();
percentProgress = (*mySupervisingDoc->calc) ();
return ( (percentProgress*maxSteps) / 100 );
} /* CMakingProgress::Calculate */
void CMeter::StartProgress (void) {
progressO->start = true;
} /* StartProgress */
void CMeter::UpdateProgress (void) {
short inStep; /* Local in case Calculate() moves memory
** when it calls your passed function = calc. */
Rect sliderRect;
long finalTicks;
Str255 complete = "\pTask is complete !!!";
inStep = progressO->Calculate();
while (inStep <= progressO->maxSteps) {
progressO->currStep = inStep;
progressO->Draw(&sliderRect);
inStep = progressO->Calculate();
}
CopyPString(complete, ( (CMeterMainPane*)itsMainPane )->mTitle);
EndProgress();
Delay(180, &finalTicks); /* Ain't she pretty !!! */
Dispose();
SysBeep(10);
} /* CMeter::UpdateProgress */
void CMeter::EndProgress (void) {
LongRect frameLR;
Rect windSR;
progressO->start = false;
progressO->currStep = 0;
itsMainPane->GetFrame(&frameLR);
itsMainPane->FrameToWindR(&frameLR, &windSR);
itsMainPane->DrawAll(&windSR);
} /* EndProgress */
void CMeter::Dispose (void) {
inherited::Dispose();
} /* Dispose */
/* { end file "CMeter.c" } */